package com.tt.whorlviewlibrary;

import static com.tt.whorlviewlibrary.TypedArraySetting.WHORL_VIEW_CIRCLE_COLORS;
import static com.tt.whorlviewlibrary.TypedArraySetting.WHORL_VIEW_CIRCLE_SPEED;
import static com.tt.whorlviewlibrary.TypedArraySetting.WHORL_VIEW_PARALLAX;
import static com.tt.whorlviewlibrary.TypedArraySetting.WHORL_VIEW_STROKE_WIDTH;
import static com.tt.whorlviewlibrary.TypedArraySetting.WHORL_VIEW_SWEEP_ANGLE;

import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.Arc;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;

/**
 * 类似螺纹的加载view<br>
 * 可以自定义的属性：颜色、旋转速度（X弧度/s）<br>
 * Created by Kyson on 2015/8/9.<br>
 * www.hikyson.cn<br>
 */
public class WhorlView extends Component implements Component.DrawTask {
    public static final int FAST = 1;
    public static final int MEDIUM = 0;
    public static final int SLOW = 2;

    private static final String COLOR_SPLIT = "_";
    private boolean isMeasure = true;
    private static final int PARALLAX_FAST = 60;
    private static final int PARALLAX_MEDIUM = 72;
    private static final int PARALLAX_SLOW = 90;
    private static final long REFRESH_DURATION = 16L;

    // 当前动画时间
    private long mCircleTime;
    // 每层颜色
    private int[] mLayerColors;
    // 旋转速度
    private int mCircleSpeed;
    // 视差差速
    private int mParallaxSpeed;
    // 弧长
    private float mSweepAngle;
    // 弧宽
    private float mStrokeWidth;

    public WhorlView(Context context) {
        this(context, null);
    }

    public WhorlView(Context context, AttrSet attrs) {
        this(context, attrs, 0);
    }

    public WhorlView(Context context, AttrSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(attrs);
    }

    private void init(AttrSet attrs) {
        // 默认外层最慢270度/s
        final int defaultCircleSpeed = 270;
        final float defaultSweepAngle = 90f;
        final float defaultStrokeWidth = 5f;
        final String defaultColors = "#F44336_#4CAF50_#5677fc";
        if (attrs != null) {
            String colors =
                    attrs.getAttr(WHORL_VIEW_CIRCLE_COLORS).isPresent()
                            ? attrs.getAttr(WHORL_VIEW_CIRCLE_COLORS).get().getStringValue()
                            : defaultColors;
            parseStringToLayerColors(colors);

            mCircleSpeed =
                    attrs.getAttr(WHORL_VIEW_CIRCLE_SPEED).isPresent()
                            ? attrs.getAttr(WHORL_VIEW_CIRCLE_SPEED).get().getIntegerValue()
                            : defaultCircleSpeed;
            int index =
                    attrs.getAttr(WHORL_VIEW_PARALLAX).isPresent()
                            ? attrs.getAttr(WHORL_VIEW_PARALLAX).get().getIntegerValue()
                            : MEDIUM;
            setParallax(index);

            mSweepAngle =
                    attrs.getAttr(WHORL_VIEW_SWEEP_ANGLE).isPresent()
                            ? attrs.getAttr(WHORL_VIEW_SWEEP_ANGLE).get().getFloatValue()
                            : defaultSweepAngle;
            if (mSweepAngle <= 0 || mSweepAngle >= 360) {
                throw new IllegalArgumentException("sweep angle out of bound");
            }

            mStrokeWidth =
                    attrs.getAttr(WHORL_VIEW_STROKE_WIDTH).isPresent()
                            ? attrs.getAttr(WHORL_VIEW_STROKE_WIDTH).get().getFloatValue()
                            : defaultStrokeWidth;

        } else {
            parseStringToLayerColors(defaultColors);
            mCircleSpeed = defaultCircleSpeed;
            mParallaxSpeed = PARALLAX_MEDIUM;
            mSweepAngle = defaultSweepAngle;
            mStrokeWidth = defaultStrokeWidth;
        }

        addDrawTask(this);
    }

    /**
     * string类型的颜色分割并转换为色值
     *
     * @param colors
     */
    private void parseStringToLayerColors(String colors) {
        String[] colorArray = colors.split(COLOR_SPLIT);
        mLayerColors = new int[colorArray.length];
        for (int i = 0; i < colorArray.length; i++) {
            try {
                mLayerColors[i] = Color.getIntColor(colorArray[i]);
            } catch (IllegalArgumentException ex) {
                throw new IllegalArgumentException(
                        "whorlview_circle_colors can not be parsed | " + ex.getLocalizedMessage());
            }
        }
    }

    private void setParallax(int index) {
        switch (index) {
            case FAST:
                mParallaxSpeed = PARALLAX_FAST;
                break;
            case MEDIUM:
                mParallaxSpeed = PARALLAX_MEDIUM;
                break;
            case SLOW:
                mParallaxSpeed = PARALLAX_SLOW;
                break;
            default:
                throw new IllegalStateException("no such parallax type");
        }
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        if (isMeasure) {
            isMeasure = false;
            onMyMeasure(component);
        }
        for (int i = 0; i < mLayerColors.length; i++) {
            float angle = (mCircleSpeed + mParallaxSpeed * i) * mCircleTime * 0.001f;
            drawArc(canvas, i, angle);
        }
    }

    private boolean mIsCircling = false;

    /**
     * start anim
     */
    public void start() {
        mIsCircling = true;
        new Thread(
                        new Runnable() {
                            @Override
                            public void run() {
                                mCircleTime = 0L;
                                while (mIsCircling) {
                                    invalidateWrap();
                                    mCircleTime = mCircleTime + REFRESH_DURATION;
                                    try {
                                        Thread.sleep(REFRESH_DURATION);
                                    } catch (InterruptedException e) {
                                        e.printStackTrace();
                                    }
                                }
                            }
                        })
                .start();
    }

    public void stop() {
        mIsCircling = false;
        mCircleTime = 0L;
        invalidateWrap();
    }

    public boolean isCircling() {
        return mIsCircling;
    }

    private void invalidateWrap() {
        new EventHandler(EventRunner.getMainEventRunner())
                .postTask(
                        new Runnable() {
                            @Override
                            public void run() {
                                invalidate();
                            }
                        });
    }

    /**
     * 画弧
     *
     * @param canvas
     * @param index      由内而外
     * @param startAngle
     */
    private void drawArc(Canvas canvas, int index, float startAngle) {
        Paint paint = checkArcPaint(index);
        // 最大圆是view的边界

        RectFloat oval = checkRectF(index);
        canvas.drawArc(oval, new Arc(startAngle, mSweepAngle, false), paint);
    }

    private Paint mArcPaint;

    private Paint checkArcPaint(int index) {
        if (mArcPaint == null) {
            mArcPaint = new Paint();
        } else {
            mArcPaint.reset();
        }
        mArcPaint.setColor(new Color(mLayerColors[index]));
        mArcPaint.setStyle(Paint.Style.STROKE_STYLE);
        mArcPaint.setStrokeWidth(mStrokeWidth);
        mArcPaint.setAntiAlias(true);
        return mArcPaint;
    }

    private RectFloat mOval;

    private RectFloat checkRectF(int index) {
        if (mOval == null) {
            mOval = new RectFloat();
        }
        float start = index * (mStrokeWidth + mIntervalWidth) + mStrokeWidth / 2;
        float end = getMinLength() - start;
        mOval.left = start;
        mOval.top = start;
        mOval.right = end;
        mOval.bottom = end;
        return mOval;
    }

    private int getMinLength() {
        return Math.min(getWidth(), getHeight());
    }

    private float mIntervalWidth;

    private void onMyMeasure(Component component) {
        int minSize = (int) (mStrokeWidth * 4 * mLayerColors.length + mStrokeWidth);
        int wantSize = (int) (mStrokeWidth * 8 * mLayerColors.length + mStrokeWidth);
        int size = measureSize(component.getWidth(), wantSize, minSize);
        calculateIntervalWidth(size);
        component.setWidth(size);
        component.setHeight(size);
    }

    /**
     * 计算间隔大小
     *
     * @param size
     */
    private void calculateIntervalWidth(int size) {
        float wantIntervalWidth = (size / (mLayerColors.length * 2)) - mStrokeWidth;
        // 防止间隔太大，最大为弧宽的3倍
        float maxIntervalWidth = mStrokeWidth * 4;
        mIntervalWidth = Math.min(wantIntervalWidth, maxIntervalWidth);
    }

    /**
     * 测量view的宽高
     *
     * @param measureSpec
     * @param wantSize
     * @param minSize
     * @return int
     */
    public static int measureSize(int measureSpec, int wantSize, int minSize) {
        int result = 0;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        if (specMode == 1) {
            // 父布局想要view的大小
            result = specSize;
        } else {
            result = wantSize;
            if (specMode == 2) {
                // wrap_content
                result = Math.min(result, specSize);
            }
        }
        // 测量的尺寸和最小尺寸取大
        return Math.max(result, minSize);
    }
}
